﻿using Grafo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Modelo
{
    public class Bus
    {
        private int CON_CUPO = 0;
        private int SIN_CUPO = 1;
        private int CON_SOBRECARGA = 2;
        private Boolean EN_ESTACION = true;
        private Boolean EN_VIA = false;
        private int _sobrecupo;
        private int _capacidad;
        private int _estadoCapacidad;
        private int _posicion;
        private double _velocidad; // en m/min
        private double _velocidadTemp;
        private string _placa;
        private Boolean _estado;        
        private List<Pasajero> _pasajeros;
        private Ruta _ruta;
        private int _flotaTotal = 0;
        private int _flotaTemp;
        private double _frecuencia = 0;// en buses por min
        private double[]_distanciasIda;
        private double[] _distanciasVuelta;
        private int _orientacion;

        public Bus(String placa, int orientacion, int capacidad, int sobrecupo,double velocidad, Ruta ruta, int flotaTotal, double frecuencia)
        {
            _placa = placa;
            _velocidad = (velocidad/60)*1000;//conversion de km/h a m/min
            _velocidadTemp = _velocidad;
            _posicion = 0;
            _capacidad = capacidad;
            _sobrecupo = sobrecupo;
            _ruta = ruta;
            _estadoCapacidad = CON_CUPO;
            _pasajeros = new List<Pasajero>();
            _estado = EN_ESTACION;
            _flotaTotal = flotaTotal;
            _frecuencia = 60/frecuencia; // convertir de buses/hora a buses/minuto
            _orientacion = orientacion;
            _distanciasIda = new double[ruta.darListaRecorridoIda().Count];
            _distanciasVuelta= new double[ruta.darListaRecorridoVuelta().Count];
            _distanciasIda[0]= 0;
            _distanciasVuelta[0]=0;
            _flotaTemp = _flotaTotal;
            prepararParaInciarRecorridoIda();
            prepararParaInciarRecorridoVuelta();
        }

        public Ruta darRuta()
        {
            return _ruta;
        }

        public Boolean dondeSeEncuentraBus(){
            return _estado;
        }

        public int darEstadoCapacidadBus()
        {
            return _estadoCapacidad;
        }

        public int darFlotaTotal()
        {
            return _flotaTotal;
        }

        public double darFrecuencia()
        {
            return _frecuencia;
        }

        public string darPlaca()
        {
            return _placa;
        }

        public int darOrientacion()
        {
            return _orientacion;
        }

        public int darCapacidad()
        {
            return _capacidad;
        }

        public int darSobrecupo()
        {
            return _sobrecupo;
        }

        public double darVelocidad()
        {
            return _velocidad;
        }

        public int darFlotaTemp()
        {
            return _flotaTemp;
        }

        public void cambiarFlotaTemp(int nuevoValor)
        {
            _flotaTemp = nuevoValor;
        }
        public Boolean recibirPasajero(Pasajero pasajero)
        {
            bool salida = false;
            int cupoActual = _pasajeros.Count();
            if (cupoActual < _capacidad)
            {
                _pasajeros.Add(pasajero);
                salida = true;
                if ((cupoActual + 1) == _capacidad)
                {
                    _estadoCapacidad = SIN_CUPO;
                }
                else
                {
                    _estadoCapacidad = CON_CUPO;
                }
            }
            else
            {
                if (cupoActual < (_capacidad + _sobrecupo))
                {
                    _pasajeros.Add(pasajero);
                    salida = true;
                    _estadoCapacidad = CON_SOBRECARGA;
                }
            }
            return salida;
        }

        /*
        public Boolean descargarPasajero()
        {
            bool salida = false;
            int cupoActual = _pasajeros.Count();
            foreach (Pasajero p in _pasajeros)
            {
                if (p.Equals(pasajero))
                {
                    _pasajeros.Remove(pasajero);
                    e.ingresarPasajero(pasajero);
                    salida = true;
                }
            }
            return salida;
        }
        */
        public void prepararParaInciarRecorridoIda()
        {
            Grafo<Estacion> g = _ruta.darGrafoParadas();
            List<String> rutas=_ruta.darListaRecorridoIda();
            string estOrigen ="*";
            string estDestino;
            int cont = 1;
            foreach(string estacion in rutas){
                 estDestino= estacion;
                if (estOrigen.Equals("*"))
                {
                    estOrigen = estacion;
                }
                else
                {
                    Estacion o = buscarEstacion(g,estOrigen);
                    Estacion d = buscarEstacion(g, estDestino);
                    double metros = g.darPesoArista(o, d);
                    _distanciasIda[cont]=metros;
                    cont++;
                    estOrigen = estDestino;
                }
            }
        }


        public void prepararParaInciarRecorridoVuelta()
        {
            Grafo<Estacion> g = _ruta.darGrafoParadas();
            List<String> rutas = _ruta.darListaRecorridoVuelta();
            string estOrigen = "*";
            string estDestino;
            int cont = 1;
            foreach (string estacion in rutas)
            {
                estDestino = estacion;
                if (estOrigen.Equals("*"))
                {
                    estOrigen = estacion;
                }
                else
                {
                    Estacion o = buscarEstacion(g, estOrigen);
                    Estacion d = buscarEstacion(g, estDestino);
                    double metros = g.darPesoArista(o, d);
                    _distanciasVuelta[cont] = metros;
                    cont++;
                    estOrigen = estDestino;
                }
            }
        }

        public string avanzar()
        {
            if (_orientacion == 0)
            {
                return avanceIda();
            }
            else
            {
                return avanceVuelta();
            }
        }

        private string avanceIda()
        {
            double proximo = _distanciasIda[_posicion];
            double resultado = _velocidadTemp - proximo;

            if (resultado>=0)
            {
                _estado = EN_ESTACION;
                List<String> est = _ruta.darListaRecorridoIda();
                int count = -1;
                foreach (string estacion in est)
                {
                    count++;
                    if (count == _posicion)
                    {
                        return estacion;
                    }
                }
                _posicion++;

                if(_posicion==_distanciasIda.Length){
                    _orientacion = 1;
                    _posicion = 0;
                    _velocidadTemp = _velocidad;
                }
            }
            else
            {
                _velocidadTemp += _velocidadTemp;
                _estado = EN_VIA; 
            }
            return "EN VIA";
        }

        private string avanceVuelta()
        {
            double proximo = _distanciasVuelta[_posicion];
            double resultado = _velocidadTemp - proximo;

            if (resultado >= 0)
            {
                _estado = EN_ESTACION;
                List<String> est = _ruta.darListaRecorridoIda();
                int count = -1;
                foreach (string estacion in est)
                {
                    count++;
                    if (count == _posicion)
                    {
                        return estacion;
                    }
                }
                _posicion++;

                if (_posicion == _distanciasVuelta.Length)
                {
                    _orientacion = 0;
                    _posicion = 1;
                    _velocidadTemp = _velocidad;
                }
            }
            else
            {
                _velocidadTemp += _velocidadTemp;
                _estado = EN_VIA;
            }
            return "EN VIA";
        }


        public Estacion buscarEstacion(Grafo<Estacion> grafo, string nombreEstacion)
        {
            List<Estacion> estaciones=grafo.darVertices();
            foreach(Estacion est in estaciones){
                if(est.darNombre()==nombreEstacion){
                    return est;
                }
            }
            return null;
        }
    }
}
